package owlreasoner;

import org.coode.owlapi.manchesterowlsyntax.ManchesterOWLSyntaxEditorParser;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.expression.OWLEntityChecker;
import org.semanticweb.owlapi.expression.ParserException;
import org.semanticweb.owlapi.expression.ShortFormEntityChecker;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.owllink.*;
import org.semanticweb.owlapi.owllink.builtin.requests.CreateKB;
import org.semanticweb.owlapi.owllink.builtin.requests.GetEquivalentClasses;
import org.semanticweb.owlapi.owllink.builtin.requests.GetSubClasses;
import org.semanticweb.owlapi.owllink.builtin.requests.LoadOntologies;
import org.semanticweb.owlapi.owllink.builtin.response.KB;
import org.semanticweb.owlapi.owllink.builtin.response.OWLlinkErrorResponseException;
import org.semanticweb.owlapi.owllink.builtin.response.SetOfClassSynsets;
import org.semanticweb.owlapi.owllink.builtin.response.SetOfClasses;
import org.semanticweb.owlapi.owllink.server.OWLlinkServer;
import org.semanticweb.owlapi.owllink.server.serverfactory.PelletServerFactory;
import org.semanticweb.owlapi.reasoner.Node;
import org.semanticweb.owlapi.util.BidirectionalShortFormProvider;
import org.semanticweb.owlapi.util.BidirectionalShortFormProviderAdapter;
import org.semanticweb.owlapi.util.SimpleShortFormProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 *
 * @author Sarala Wimalaratne
 * Date: 13-Dec-2011
 * Time: 21:50:25
 */
public class ReasonerService {

    private IRI docIRI;
    private String ou;
    private String port;
    private String url;

    private OWLlinkReasoner reasoner =null;
    private OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
    private OWLOntology queryOntology =null;
    private OWLlinkServer server = null;

    public ReasonerService(){
        Properties configFile = new Properties();
        try {
            FileInputStream in =  new FileInputStream("config.properties");
            configFile.load(in);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        docIRI=IRI.create(new File(configFile.getProperty("KBOWL")));
        ou =configFile.getProperty("KB_NS");
        port = configFile.getProperty("PORT");
        url =  configFile.getProperty("SERVER_URL")+":"+port;
    }

    public void setUpServices(){
        setUpReasoner();
        setUpManQuery();
    }

    private void setUpReasoner(){
        OWLlinkHTTPXMLReasonerFactory factory = new OWLlinkHTTPXMLReasonerFactory();
        try{
            OWLlinkReasonerConfiguration reasonerConfiguration = new OWLlinkReasonerConfiguration(new URL(url));
            reasoner = factory.createNonBufferingReasoner(manager.createOntology(), reasonerConfiguration);
        }catch (OWLlinkReasonerIOException e){            
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (OWLOntologyCreationException e) {
            e.printStackTrace();
        }
    }

    private void setUpManQuery(){
        try {
            queryOntology = manager.loadOntology(docIRI);
        } catch (OWLOntologyCreationException e) {
            e.printStackTrace();
        }
    }

    public void startPelletServer(){
        PelletServerFactory pellet = new PelletServerFactory();
        server = pellet.createServer(Integer.parseInt(port));
        server.run();
    }

    public void stopPelletServer(){
        if(server!=null) {
            try {
                server.stop();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void createKB(){
        try {
            CreateKB createKBRequest = new CreateKB(IRI.create(ou));
            KB kbResponse = reasoner.answer(createKBRequest);
            reasoner.answer(new LoadOntologies(kbResponse.getKB(),docIRI));
        } catch (OWLlinkErrorResponseException e) {
            e.printStackTrace();
        }
    }

    private Response executeReasoner(Request request){
        Response response = null;
        try{
            response = reasoner.answer(request);
        }catch(OWLlinkReasonerIOException e){
            e.printStackTrace();
        }
        return response;
    }

    private OWLClassExpression runManchesterQuery(String manchesterQuery){
        ManchesterOWLSyntaxEditorParser parser = new ManchesterOWLSyntaxEditorParser(manager.getOWLDataFactory(), manchesterQuery);
        parser.setDefaultOntology(queryOntology);
        Set<OWLOntology> importsClosure = queryOntology.getImportsClosure();
        BidirectionalShortFormProvider bidiShortFormProvider = new BidirectionalShortFormProviderAdapter(manager, importsClosure, new SimpleShortFormProvider());
        OWLEntityChecker entityChecker = new ShortFormEntityChecker(bidiShortFormProvider);
        parser.setOWLEntityChecker(entityChecker);

        OWLClassExpression classExp=null;
        try {
            classExp = parser.parseClassExpression();
        } catch (ParserException e) {
            e.printStackTrace();
        }

        return classExp;
    }

    public ArrayList<String> getSubTerms(String query) {
        OWLClassExpression exp = runManchesterQuery(query);
        ArrayList<String> idList = new ArrayList<String>();
        if(exp!=null){
            GetSubClasses getSubClasses = new GetSubClasses(IRI.create(ou), exp);
            SetOfClassSynsets synsets = (SetOfClassSynsets)executeReasoner(getSubClasses);
            for (Object synset : synsets) {
                Node<OWLClass> owlClassNode = (Node<OWLClass>) synset;
                idList.add(owlClassNode.getEntities().iterator().next().toStringID());
            }
        }
        return idList;
    }


    public ArrayList<String> getEquivalentTerms(String query){
        OWLClassExpression exp = runManchesterQuery(query);
        ArrayList<String> idList = new ArrayList<String>();
        if(exp!=null){
            GetEquivalentClasses getEquivalentClasses = new GetEquivalentClasses(IRI.create(ou),exp);
            SetOfClasses eqclasses = (SetOfClasses)executeReasoner(getEquivalentClasses);
            for (Object eqclass : eqclasses) {
                OWLClass eqClass = (OWLClass) eqclass;
                idList.add(eqClass.toStringID());
            }
        }
        return idList;
    }



    public ArrayList<String> getTerms(String query) {
        ArrayList<String> idList = new ArrayList<String>();
        idList.addAll(getEquivalentTerms(query));
        idList.addAll(getSubTerms(query));        
        return idList;
    }

    public void printTerms(ArrayList<String> termList){
        for(String term: termList){
            System.out.println(term);
        }
    }

    public static void main(String [] args){
        ReasonerService reasonerService = new ReasonerService();
        reasonerService.startPelletServer();
        reasonerService.setUpServices();         
        reasonerService.createKB();
        reasonerService.printTerms(reasonerService.getEquivalentTerms("RICORDO_2 and part-of some RICORDO_21"));
        reasonerService.stopPelletServer();
    }

}